﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Xml.Linq;
using Microsoft.Xrm.Sdk.Metadata;

namespace VisualRibbonEditor
{
	public partial class ConnectDialog : UserControl, IDialog
	{

		public ConnectDialog()
		{
			InitializeComponent();

			this.ServerUrl.ToolTip =
				"Examples" + Environment.NewLine +
				"On-Premises: http://crmservername:5555" + Environment.NewLine +
				"Hosted/IFD: https://orgname.domain.com" + Environment.NewLine +
				"CRM Online: https://orgname.crm.dynamics.com";

			Connection emptyConnection = Connection.EmptyConnection;
			ConnectionProfiles.Items.Add(emptyConnection);
			Connection connection = new Connection();
			if (!String.IsNullOrWhiteSpace(connection.ServerUrl))
			{
				int index;
				foreach(Connection cItem in connection.Connections)
				{
					index = ConnectionProfiles.Items.Add(cItem);
					if (cItem.GetId() == connection.GetId())
					{
						this.ConnectionProfiles.SelectedIndex = index;
					}
				}
				StartProgChange();
				ServerUrl.Text = connection.ServerUrl;
				OrgName.Text = connection.OrgName;
				Login.Text = connection.Login;
				Password.Password = connection.Password;
				ADFSMode.IsChecked = connection.ADFSMode;
				SaveConnectionInfo.IsChecked = true;
				SavePassword.IsEnabled = true;
				SavePassword.IsChecked = !String.IsNullOrWhiteSpace(connection.SecurePassword);
				EntityName.Text = connection.EntityName;
				StopProgChange();
			}
		}
		private bool _programmaticChange = false;
		private void StartProgChange() { _programmaticChange = true; }
		private void StopProgChange() { _programmaticChange = false; }
		private void OKButton_Click(object sender, RoutedEventArgs e)
		{
			// * Validation
			#region Validation
			if (String.IsNullOrEmpty(this.ServerUrl.Text))
			{
				MessageBox.Show("You must enter a server url.");
				return;
			}
			StartProgChange();
			this.ServerUrl.Text = this.ServerUrl.Text.Trim();
			StopProgChange();
			if (!Uri.IsWellFormedUriString(this.ServerUrl.Text, UriKind.Absolute))
			{
				MessageBox.Show("Please specify valid server url, e.g.: " + Environment.NewLine + Environment.NewLine +
					"On-Premises: http://crmservername:5555" + Environment.NewLine +
					"Hosted/IFD: https://orgname.domain.com" + Environment.NewLine +
					"CRM Online: https://orgname.crm.dynamics.com");
				return;
			}
			if ((this.ADFSMode.IsChecked == null || this.ADFSMode.IsChecked.Value == false) && String.IsNullOrEmpty(this.OrgName.Text) && !this.ServerUrl.Text.ToLowerInvariant().Contains(".dynamics.com"))
			{
				MessageBox.Show("You must enter organization name.");
				return;
			}
			if (this.ServerUrl.Text.ToLowerInvariant().Contains(".dynamics.com") &&
				(string.IsNullOrEmpty(this.Password.Password) || string.IsNullOrEmpty(this.Login.Text)))
			{
				MessageBox.Show("You must enter your login and password when connecting to CRM Online");
				return;
			}

			try
			{
				Uri url = new Uri(this.ServerUrl.Text);
			}
			catch
			{
				MessageBox.Show("Invalid Server Url");
				return;
			}

			if (!ServerUrl.Text.StartsWith("http"))
			{
				MessageBox.Show("Invalid Server Url. Url must start with http:// or https://");
				return;
			}
			#endregion Validation

			if (MainWindow.CurrentSolution.IsLoaded()) //
			{
				MessageBoxResult reload = MessageBox.Show(
					"This will close your currently opened entity." + Environment.NewLine +
					"All unsaved changes will be lost." + Environment.NewLine +
					"Would you like to continue?",
					"Close current entity?", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
				if (reload == MessageBoxResult.No) return;
				MainWindow.CurrentSolution = new Solution();
				MainWindow.CurrentMainPage.ClearEntityNameStatus();
				MainWindow.CurrentMainPage.ClearServerVersionStatus();
				MainWindow.CurrentMainPage.ClearAndDisableUI();
			}


			// Clear OrgName for ADFS connections
			if (this.ADFSMode.IsChecked != null && this.ADFSMode.IsChecked.Value == true) { StartProgChange(); this.OrgName.Text = String.Empty; StopProgChange(); }

			Connection c = new Connection();
			c.ServerUrl = this.ServerUrl.Text;
			c.Login = this.Login.Text;
			c.OrgName = this.OrgName.Text;
			c.Password = this.Password.Password;
			c.ADFSMode = this.ADFSMode.IsChecked.Value;
			c.EntityName = this.EntityName.Text;

			Testing.Visibility = Visibility.Visible;
			this.IsEnabled = false;
			this.DeleteConnectionImage.OpacityMask.Opacity = 0.5;

			//test the connection info

			MainWindow.CurrentMainPage.ShowConnectionStatus("Testing connection to {OrgName} on {ServerHostName} {ServerType}", c);

			c.TestConnection(false, true, (passed, errorDescription) =>
			{
				Testing.Visibility = Visibility.Collapsed;
				this.IsEnabled = true;

				if (passed)
				{
					MainWindow.CurrentMainPage.ShowConnectionStatus("Connected to {OrgName} on {ServerHostName} {ServerType}", c);
					c.SaveConnectionInfo = (SaveConnectionInfo.IsChecked != null && SaveConnectionInfo.IsChecked.Value);
					c.SavePasswords = (SavePassword.IsChecked != null && SavePassword.IsChecked.Value);
					c.IsConnected = true;
					this.SaveConnections(c);

					Connection.CurrentConnection = c;

					if (DialogClosed != null)
					{
						DialogClosed(true);
					}
				}
				else
				{
					string errorMessage = "Failed to connect to CRM.";
					if (!String.IsNullOrEmpty(errorDescription)) errorMessage += (Environment.NewLine + errorDescription);
					MainWindow.CurrentMainPage.ShowConnectionStatus("Failed to connect to {OrgName} on {ServerHostName}", c);
					MessageBox.Show(errorMessage);
				}
			});
		}

		private void SaveConnections(Connection c)
		{
			bool existing = false;
			foreach (Connection connection in c.Connections)
			{
				if (c.GetId() == connection.GetId())
				{
					// Modify existing Connection
					connection.Password = c.Password;
					connection.ADFSMode = c.ADFSMode;
					connection.EntityName = c.EntityName;
					existing = true;
					break;
				}
			}
			if (!existing) c.Connections.Add(c); // Create new entry in Connections list
			c.Save();
		}

		/// <summary>
		/// user clicked the cancel button. Call DialogClose event with NULL to indicate a cancel.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void CancelButton_Click(object sender, RoutedEventArgs e)
		{
			if (DialogClosed != null)
			{
				DialogClosed(null);
			}
		}

		public event CloseDialogHandler DialogClosed;

		private void ConnectDialog_KeyUp(object sender, KeyEventArgs e)
		{
			switch (e.Key) //
			{
				// ENTER
				case Key.Enter:
					OKButton_Click(sender, new RoutedEventArgs());
					break;
				// ESC
				case Key.Escape:
					if (DialogClosed != null) DialogClosed(null);
					break;
				default:
					break;
			}
		}

		private void SaveConnectionInfo_Click(object sender, RoutedEventArgs e)
		{
			if (SaveConnectionInfo.IsChecked != null && SaveConnectionInfo.IsChecked.Value)
			{
				Connection.CurrentConnection.SaveConnectionInfo = true;
				SavePassword.IsEnabled = true;
			}
			else
			{
				Connection.CurrentConnection.SaveConnectionInfo = false;
				SavePassword.IsEnabled = false;
				SavePassword.IsChecked = false;
			}
		}

		private void ServerUrl_LostFocus(object sender, RoutedEventArgs e)
		{
			if (this.ServerUrl != null && !String.IsNullOrWhiteSpace(this.ServerUrl.Text) && this.ServerUrl.Text.ToLowerInvariant().Contains(".dynamics.com"))
			{
					this.ADFSMode.IsEnabled = false;
					this.ADFSMode.IsChecked = false;
			}
			else
			{
				this.ADFSMode.IsEnabled = true;
			}
		}

		private void Connection_SelectionChanged(object sender, SelectionChangedEventArgs e)
		{
			if (this.ConnectionProfiles.SelectedIndex > 0)
			{
				this.DeleteConnection.IsEnabled = true;
				this.DeleteConnectionImage.OpacityMask.Opacity = 1;

				StartProgChange();
				Connection connection = (Connection)this.ConnectionProfiles.SelectedItem;
				ServerUrl.Text = connection.ServerUrl;
				OrgName.Text = connection.OrgName;
				Login.Text = connection.Login;
				Password.Password = connection.Password;
				ADFSMode.IsChecked = connection.ADFSMode;
				EntityName.Text = connection.EntityName;
				SaveConnectionInfo.IsChecked = Connection.CurrentConnection.SaveConnectionInfo;
				if (Connection.CurrentConnection.SaveConnectionInfo)
				{
					SavePassword.IsEnabled = true;
					SavePassword.IsChecked = !String.IsNullOrWhiteSpace(connection.SecurePassword);
				}
				StopProgChange();
			} else {
				this.DeleteConnection.IsEnabled = false;
				this.DeleteConnectionImage.OpacityMask.Opacity = 0.5;
			}
		}

		private void DeleteConnection_Click(object sender, RoutedEventArgs e)
		{
			if (this.ConnectionProfiles.SelectedIndex > 0)
			{
				int index = this.ConnectionProfiles.SelectedIndex;
				this.ConnectionProfiles.Items.RemoveAt(index);

				Connection.CurrentConnection.Connections.RemoveAt(index - 1);
				Connection.CurrentConnection.SavePasswords = (SavePassword.IsChecked != null && SavePassword.IsChecked.Value);
				Connection.CurrentConnection.Save();

				this.ConnectionProfiles.SelectedIndex = 0;
			}
		}

		private void ServerUrl_TextChanged(object sender, TextChangedEventArgs e)
		{
			if (!_programmaticChange) this.ConnectionProfiles.SelectedIndex = 0;
		}

		private void OrgName_TextChanged(object sender, TextChangedEventArgs e)
		{
			if (!_programmaticChange) this.ConnectionProfiles.SelectedIndex = 0;
		}

		private void Login_TextChanged(object sender, TextChangedEventArgs e)
		{
			if (!_programmaticChange) this.ConnectionProfiles.SelectedIndex = 0;
		}
	}
}